#!/usr/bin/env python

"""
File:      sessionManager.py
Author:    Jkuhn
Warranty:  AS IS, NO GUARANTEES TO ANY EFFECT.
License:   Lesser GNU Public License
"""

import re
import pickle

class sessionManager:

    # This datastructure stores posts in a list: [(topic, subject, user, This is the post content")]
    bbsData = []

    # This is the nested dict used to store all foreign data
    # {"server1": [("topic1", "subject1", "Bob", "post content from Bob")], 
    #  "server2": [("topic1", "subject1", "Alice", "post content from Alice")]} 
    foreignData = dict()

    allPostsList = []

    # This is a help string
    helpStr = """
    Here's what you can type:
      quit                  - exit the BBS System
      ls                    - list all posts
      ltopic                - list posts sorted by topic     
      lauthor               - list posts sorted by author
      read      [index]     - view the contents of a post
      delete    [index]     - delete a post (so long as you are the author)      
      post      topic ; title ; content
    """

    def __init__(self, dataFileName="messages.txt"):
        self.dataFileName = dataFileName
        
        #look for pre-existing data in the file
        try:
            self.importBBSData()
            self.rebuildLists()
        except:
            print "ERROR: Import BBS Data failed unexpectedly. Server will be empty"
    
    def handleInput(self, user, sdata):
        if (re.match("help", sdata, re.I)):
            return self.helpStr
        elif (re.match("ls", sdata, re.I)):
            return self.listAll()
        elif (re.match("read", sdata, re.I)):
            return self.read(self.getParam(sdata))
        elif (re.match("ltopic", sdata, re.I)):
            self.sortByTopic()
            return self.listAll()
        elif (re.match("lauthor", sdata, re.I)):
            self.sortByAuthor()
            return self.listAll()
        elif (re.match("delete", sdata, re.I)):
            return self.delete(self.getParam(sdata), user)
        elif (re.match("post", sdata, re.I)):
            return self.post(self.getParam(sdata), user)
        elif (re.match("quit", sdata, re.I)):
            exit() 
        else:
            return ""

    def getParam(self, input):
        toks = input.split()
        return " ".join(toks[1:])
                        
    def read(self, targetIndex):                
        retStr = ""        
        try:
            if type(targetIndex) != int:
                targetIndex = int(targetIndex)
            retStr += self.getNiceHeader(self.allPostsList[targetIndex]) + "\n"
            retStr += self.allPostsList[targetIndex][3] + "\n"
        except:
            retStr += "Post " + str(targetIndex) + " does not exist"
        return retStr

    def listAll(self):
        if self.allPostsList == []:
            self.rebuildLists()
        response = ""
        index = 0
        for postTuple in self.allPostsList:
            response += '[' + str(index) + ']\t' + self.getNiceHeader(postTuple) + "\n"
            index += 1
        return response

    def purge(self, serverName):   
        try: 
            del self.foreignData[serverName]
            self.rebuildLists()
        except:
            pass

    def post(self, postString, user):
        try:
            toks = postString.split(";")
            postTuple = (toks[0], toks[1], user, toks[2])
            self.bbsData.append(postTuple)
            self.allPostsList.append(postTuple)
            self.exportBBSData()
            return "New post added successfully"
        except:
            return "I'm sorry, your post failed to parse"
        

    def delete(self, index, user):  
        if type(index) != int:
            index = int(index) 
        try:
            author = self.allPostsList[index][2]            
            if re.match(author, user, re.I):
            #if re.match(author, author, re.I):
                # remove the post from bbsData, remove it from allPosts
                self.bbsData.remove(self.allPostsList[index])
                del self.allPostsList[index]
                # write the change to disk
                self.exportBBSData()
                return "Successfully deleted post"
            else:
                return "You are not authorized to delete post " + str(index)
        except:
            return "Post " + str(index) + " does not exist"

    def getNiceHeader(self, fourTuple):
        retStr = '[' + fourTuple[0] + ']'
        retStr += '[' + fourTuple[1] + ']'
        retStr += '[' + fourTuple[2] + ']'
        return retStr

    def rebuildLists(self):
        # This is where the header dict is created
        # self.postHeadersByIndex
        self.allPostsList = []
        
        # get the key-tuples from local bbsData 
        for postTuple in self.bbsData:
            self.allPostsList.append(postTuple)
        # for each foreign server
        for server in self.foreignData.keys():
            # get its list of data
            print "Foreign Data " + str(self.foreignData[server])
            for postTuple in self.foreignData[server]:
                print "Processing Foreign tuple " + str(postTuple)
                self.allPostsList.append(postTuple)
                
    def sortByTopic(self):
        #self.contentList = []
        #self.headerList = []                
        self.allPostsList = sorted(self.allPostsList, key=lambda topic: topic[0])

    def sortByAuthor(self):
        self.allPostsList = sorted(self.allPostsList, key=lambda author: author[2])


    def postEditor(self, topicName, postName):
	print "Sorry, post editor not yet implemented"

    def exportBBSData(self):
        dfile = open(self.dataFileName, "w")
        pickle.dump(self.bbsData, dfile)
        dfile.close()

    def importBBSData(self):
        dfile = open(self.dataFileName, "r")
        self.bbsData = pickle.load(dfile)
        dfile.close()

    def addForeignData(self, data, serverName):
        """ 
        This adds data from a new server.  Any existing data 
        for this server is overwritten 
        """        
        self.foreignData[serverName] = data
        self.rebuildLists()
        print "Foreign Data servers: " + str(self.foreignData.keys())

    def delForeignData(self, serverName):
        """ Delete all data from a foreign server """
        if test.has_key(serverName):
            del test[serverName]
            return True
        else:
            return False

    def terp(self):
        """ 
        This is a built in session interpreter.  Use this to test
        your session manager from the command line.  Eventually you will
        need to implement a net-terp.
        """
        print "Welcome to Rogue BBS!  If you need help, just ask."
        while(True):
            inputStr = raw_input("$> ")
            print self.handleInput("localadmin", inputStr)
	

def testDriver():
    """ This function creates a new bbs session manager with some mock data """
    sman = sessionManager()
    # launch a 'terp session
    sman.terp()
    

if __name__=="__main__":
    testDriver()
